/*
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package top.continew.admin.auth.handler;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Component;
import top.continew.admin.auth.AbstractLoginHandler;
import top.continew.admin.auth.enums.AuthTypeEnum;
import top.continew.admin.auth.model.req.WechatMiniappLoginReq;
import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.common.constant.SysConstants;
import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.common.enums.GenderEnum;
import top.continew.admin.system.enums.MessageTemplateEnum;
import top.continew.admin.system.enums.MessageTypeEnum;
import top.continew.admin.system.model.entity.user.UserDO;
import top.continew.admin.system.model.entity.user.UserSocialDO;
import top.continew.admin.system.model.req.MessageReq;
import top.continew.admin.system.model.resp.ClientResp;
import top.continew.admin.system.service.MessageService;
import top.continew.admin.system.service.UserRoleService;
import top.continew.admin.system.service.UserSocialService;
import top.continew.starter.core.autoconfigure.application.ApplicationProperties;
import top.continew.starter.core.exception.BadRequestException;

import java.time.LocalDateTime;
import java.util.Collections;

/**
 * 微信小程序登录处理器
 *
 * @author Charles7c
 * @since 2024/12/26 10:00
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WechatMiniappLoginHandler extends AbstractLoginHandler<WechatMiniappLoginReq> {

    private final WxMaService wxMaService;
    private final UserSocialService userSocialService;
    private final UserRoleService userRoleService;
    private final MessageService messageService;
    private final ApplicationProperties applicationProperties;

    @Override
    public LoginResp login(WechatMiniappLoginReq req, ClientResp client, HttpServletRequest request) {
        try {
            // 调用微信接口获取用户信息
            WxMaJscode2SessionResult sessionResult = wxMaService.getUserService().getSessionInfo(req.getCode());
            String openId = sessionResult.getOpenid();
            String unionId = sessionResult.getUnionid();
            
            log.info("微信小程序登录，openId: {}, unionId: {}", openId, unionId);
            
            // 查找是否已存在关联用户
            String source = "WECHAT_MINIAPP";
            UserSocialDO userSocial = userSocialService.getBySourceAndOpenId(source, openId);
            UserDO user;
            
            if (userSocial == null) {
                // 新用户注册
                user = this.createNewUser(req, openId, unionId);
                userSocial = this.createUserSocial(user.getId(), source, openId, unionId, sessionResult);
                this.sendSecurityMsg(user);
            } else {
                // 已存在用户，更新登录信息
                user = BeanUtil.copyProperties(userService.getById(userSocial.getUserId()), UserDO.class);
                userSocial.setMetaJson(JSONUtil.toJsonStr(sessionResult));
                userSocial.setLastLoginTime(LocalDateTime.now());
                userSocialService.saveOrUpdate(userSocial);
            }
            
            // 检查用户状态
            super.checkUserStatus(user);
            
            // 执行认证
            return super.authenticate(user, client);
            
        } catch (WxErrorException e) {
            log.error("微信小程序登录失败", e);
            throw new BadRequestException("微信登录失败：" + e.getError().getErrorMsg());
        }
    }

    @Override
    public void preLogin(WechatMiniappLoginReq req, ClientResp client, HttpServletRequest request) {
        super.preLogin(req, client, request);
        if (StpUtil.isLogin()) {
            StpUtil.logout();
        }
    }

    @Override
    public AuthTypeEnum getAuthType() {
        return AuthTypeEnum.WECHAT_MINIAPP;
    }

    /**
     * 创建新用户
     */
    private UserDO createNewUser(WechatMiniappLoginReq req, String openId, String unionId) {
        String username = "wx_" + RandomUtil.randomString(RandomUtil.BASE_CHAR, 8) + IdUtil.fastSimpleUUID().substring(0, 8);
        String nickname = StrUtil.isNotBlank(req.getNickname()) ? req.getNickname() : "微信用户" + RandomUtil.randomString(4);
        
        UserDO user = new UserDO();
        user.setUsername(username);
        user.setNickname(nickname);
        
        // 设置性别
        if (req.getGender() != null) {
            if (req.getGender() == 1) {
                user.setGender(GenderEnum.MALE);
            } else if (req.getGender() == 2) {
                user.setGender(GenderEnum.FEMALE);
            } else {
                user.setGender(GenderEnum.UNKNOWN);
            }
        } else {
            user.setGender(GenderEnum.UNKNOWN);
        }
        
        // 设置头像
        if (StrUtil.isNotBlank(req.getAvatar())) {
            user.setAvatar(req.getAvatar());
        }
        
        user.setDeptId(SysConstants.SUPER_DEPT_ID);
        user.setStatus(DisEnableStatusEnum.ENABLE);
        userService.save(user);
        
        // 分配默认角色
        userRoleService.assignRolesToUser(Collections.singletonList(SysConstants.GENERAL_ROLE_ID), user.getId());
        
        return user;
    }

    /**
     * 创建用户社交账号关联
     */
    private UserSocialDO createUserSocial(Long userId, String source, String openId, String unionId, WxMaJscode2SessionResult sessionResult) {
        UserSocialDO userSocial = new UserSocialDO();
        userSocial.setUserId(userId);
        userSocial.setSource(source);
        userSocial.setOpenId(openId);
        userSocial.setMetaJson(JSONUtil.toJsonStr(sessionResult));
        userSocial.setLastLoginTime(LocalDateTime.now());
        userSocialService.saveOrUpdate(userSocial);
        return userSocial;
    }

    /**
     * 发送安全消息
     */
    private void sendSecurityMsg(UserDO user) {
        MessageTemplateEnum template = MessageTemplateEnum.SOCIAL_REGISTER;
        MessageReq req = new MessageReq(MessageTypeEnum.SECURITY);
        req.setTitle(template.getTitle().formatted(applicationProperties.getName()));
        req.setContent(template.getContent().formatted(user.getNickname()));
        messageService.add(req, CollUtil.toList(user.getId().toString()));
    }
}